package com.tju.backend.resources.config.security;

import com.tju.backend.resources.config.security.components.WebSecurityCorsFilter;
import com.tju.backend.resources.config.security.configSecurity.*;
import com.tju.backend.resources.config.security.custom.MyAccessDeniedHandler;
import com.tju.backend.resources.config.security.custom.MyAuthenticationEntryPoint;
import com.tju.backend.resources.config.security.custom.MyAuthenticationFailureHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * Security授权配置主文件
 *
 * @ApiNote EnableWebSecurity 开启springsecurity安全模式
 * @USER: CLS
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    //登录成功处理器
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    //登录失败处理器
    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    //拦截token
    @Autowired
    private MyOncePerRequestFilter myOncePerRequestFilter;
    //处理异常
    @Autowired
    private MyAuthenticationEntryPoint myAuthenticationEntryPoint;//身份错误
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;//没有权限
    //退出处理器
    @Autowired
    private MyLogoutHandler myLogoutHandler;
    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    /**
     * 拦截请求
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //第1步：解决跨域问题。cors 预检请求放行,让Spring security 放行所有preflight request（cors 预检请求）
        http.addFilterBefore(new WebSecurityCorsFilter(), ChannelProcessingFilter.class);
        //第2步：让Security永远不会创建HttpSession，它不会使用HttpSession来获取SecurityContext
        http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().headers().cacheControl();

        //第3步：请求权限配置，
        http.authorizeRequests()
                //放行API请求，其它任何请求都必须经过身份验证.
//                .antMatchers(HttpMethod.POST, "/home/**").hasIpAddress(GlobalCall.env.getProperty("data.ClientIP"))
                .antMatchers(HttpMethod.POST, "/home/**").permitAll()
                .antMatchers(HttpMethod.GET, "/home/**").permitAll()
                //动态加载资源
                .anyRequest().access("@dynamicPermission.checkPermisstion(request,authentication)");
        //第4步：拦截账号、密码。覆盖 UsernamePasswordAuthenticationFilter过滤器
        http.addFilterAt(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        //第5步：拦截token，并检测。在 UsernamePasswordAuthenticationFilter 之前添加 JwtAuthenticationTokenFilter
        http.addFilterBefore(myOncePerRequestFilter, UsernamePasswordAuthenticationFilter.class);

        //第6步：处理异常情况：认证失败和权限不足
        http.exceptionHandling().authenticationEntryPoint(myAuthenticationEntryPoint).accessDeniedHandler(myAccessDeniedHandler);

        //第7步：登录,因为使用前端发送JSON方式进行登录，所以登录模式不设置也是可以的。
        //http.formLogin();

        //第8步：退出
        http.logout().addLogoutHandler(myLogoutHandler).logoutSuccessHandler(myLogoutSuccessHandler);
    }

    /**
     * 密码拦截器
     *
     * @return
     * @throws Exception
     */
    @Bean
    MyUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter() throws Exception {
        MyUsernamePasswordAuthenticationFilter filter = new MyUsernamePasswordAuthenticationFilter();
        //成功后处理
        filter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
        //失败后处理
        filter.setAuthenticationFailureHandler(myAuthenticationFailureHandler);

        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }
}
